import { PropsResult, Scope } from "../../../typings/traverse";
import { PixijsvueComponentConfig } from "../../../typings/main";
import { deepCopy } from "../../../utils/deepCopy";
import {
  getProps,
  preResAttributeLoad,
  checkNamespace,
  absolutePath,
  getGoalData,
} from "../../../utils";
import { Pixijsvue } from "../../main";
interface DealGoalComponent {
  components: Record<string, PixijsvueComponentConfig> | undefined;
  _globalComponents: Record<string, PixijsvueComponentConfig>;
}

/**
 * 局部组件配置覆盖全局组件配置
 */
export function getComponentConfig(
  goal: DealGoalComponent,
  tagName: string
): PixijsvueComponentConfig | undefined {
  let pixijsvueComponentConfig: PixijsvueComponentConfig | undefined;
  const { components, _globalComponents } = goal;
  if (components) {
    pixijsvueComponentConfig = components[tagName];
    if (!pixijsvueComponentConfig) {
      // globalComponent 处理
      pixijsvueComponentConfig = _globalComponents[tagName];
    }
  } else {
    // globalComponent 处理
    pixijsvueComponentConfig = _globalComponents[tagName];
  }
  return pixijsvueComponentConfig;
}

/**
 * 初始化配置PixijsvueComponentConfig
 */
export function initComponentConfig(
  goal: { _data: Record<string, any> },
  pixijsvueComponentConfig: PixijsvueComponentConfig,
  ele: Element,
  scope?: Scope
) {
  const { data, props } = pixijsvueComponentConfig;
  const { _data } = goal;
  let config: PixijsvueComponentConfig = deepCopy(pixijsvueComponentConfig);
  if (data) {
    let otherData: Record<string, any>;
    if (typeof data == "function") {
      otherData = data();
    } else {
      otherData = data;
    }
    // 子组件data中不应该有与prop中重名的变量名
    if (props) {
      Object.keys(props).forEach((key) => {
        if (otherData) {
          if (otherData[key]) {
            throw new Error("props中的属性名与data中重复");
          }
        }
      });
    }
    config.data = otherData;
  }
  if (props) {
    Object.keys(props).forEach((key) => {
      let propGoal: Partial<PropsResult> = getProps(ele, key, false);
      if (!propGoal.path) {
        propGoal = getProps(ele, key, true);
      }
      if (propGoal.path) {
        if (!config.data) {
          config.data = {};
        }
        // 是否为v-bind
        if (propGoal.isResponsive) {
          // entry (scope, path): propPath
          let propPath: string = preResAttributeLoad(propGoal.path);
          if (scope) {
            const { item, items } = scope;
            let isPropNamespace = checkNamespace(propPath, item);
            if (isPropNamespace) {
              propPath = absolutePath(items, item, propPath);
            }
          }
          // 目前来说，PixiVue初始化时，会深拷贝config.data，所以父子间不会出现引用关系
          (<Record<string, any>>config.data)[key] = getGoalData(
            <object>_data,
            propPath
          );
        } else {
          (<Record<string, any>>config.data)[key] = propGoal.path;
        }
      }
    });
  }
  return config;
}

/**
 * 子组件创建后，用来绑定父子间数据传递
 */
export function bindDataToSub(goal: {
  $watcher: Record<string, Record<string, Function[]>>;
  $data: Record<string, any>;
  pixijsvueComponent: Pixijsvue
}, ele: Element, props?: Record<string, Function>, scope?: Scope) {
  const depName = "data";
  const { $data, $watcher, pixijsvueComponent } = goal;
  if (props) {
    Object.keys(props).forEach((key) => {
      let propGoal: Partial<PropsResult> = getProps(ele, key, false);
      if (!propGoal.path) {
        propGoal = getProps(ele, key, true);
      }
      if (propGoal.path) {
        if (propGoal.isResponsive) {
          let propPath: string = preResAttributeLoad(propGoal.path);
          if (scope) {
            const { item, items } = scope;
            let isPropNamespace = checkNamespace(propPath, item);
            if (isPropNamespace) {
              propPath = absolutePath(items, item, propPath);
            }
          }
          if ($watcher[depName][propPath]) {
            $watcher[depName][propPath] = [];
          }
          let cb = () => {
            pixijsvueComponent.$data[key] = getGoalData($data, propPath);
          };
          $watcher[depName][propPath].push(cb);
        }
      }
    });
  }
}
export * from './dealWith/Listeners';
